<template>
  <mu-dialog
    :open="loginDialogVisible"
    @update:open="checkLoginDialogVisible($event)"
  >
    <el-tabs v-model="tab">
      <el-tab-pane label="密码登录" name="password">
        <div>
          <mu-text-field
            v-model="form.tele"
            :full-width="true"
            label="手机号码/邮箱"
          ></mu-text-field>
          <mu-text-field
            v-model="form.account.password"
            :full-width="true"
            label="密码"
            :action-icon="showPassword ? 'visibility_off' : 'visibility'"
            :action-click="() => (showPassword = !showPassword)"
            :type="showPassword ? 'text' : 'password'"
          ></mu-text-field>
          <mu-button @click="login" color="info">登录</mu-button>
          <mu-button
            slot="actions"
            flat
            color="primary"
            @click="closeSimpleDialog"
            >取消</mu-button
          >
        </div>
      </el-tab-pane>
      <el-tab-pane label="二维码登录" name="qrcode">
        <div class="qrcode-box">
          <div class="qrcode-mask" v-if="!qrcode.src || qrcode.expired" @click="checkQrCode()">
            <span class="icon-span iconfont icon-refresh"></span>
          </div>
          <div class="img-box" style="display: flex; justify-content: center; align-items: center;">
            <img :src="qrcode.src" v-if="qrcode.src" />
            <span v-else style="color: #f8f8f8;font-size:0.1rem">网络故障</span>
          </div>
        </div>
        <div style="margin-top: 0.2rem">使用网易云音乐APP扫码登录</div>
      </el-tab-pane>
      
      <el-tab-pane label="注册" name="phone">
        <div class="login-container">
          <mu-text-field
            v-model="form.tele"
            :full-width="true"
            label="手机号码"
            :error-text="form.teleErrorText"
          ></mu-text-field>
          <div class="verify-code-box">
            <mu-text-field
              v-model="form.phone.code"
              :full-width="true"
              label="验证码"
              :error-text="form.phone.codeErrorText"
            ></mu-text-field>
            <div class="verify-code-right">
              <mu-button color="info"
                @click="sendVerifyCode().then()"
                :full-width="true"
                :disabled="isCooling"
              >
                <span>发送验证码</span
                ><span v-if="isCooling">({{ coolingTime }})s</span>
              </mu-button>
            </div>
          </div>
          <mu-text-field
            v-model="form.phone.password"
            :full-width="true"
            label="密码"
            :error-text="form.phone.passwordErrorText"
            :action-icon="showPassword ? 'visibility_off' : 'visibility'"
            :action-click="() => (showPassword = !showPassword)"
            :type="showPassword ? 'text' : 'password'"
          ></mu-text-field>
          <mu-button @click="register" full-width color="info">登录</mu-button>
        </div>
      </el-tab-pane>
    </el-tabs>
  </mu-dialog>
</template>
<script lang="ts">
import { APIType } from "@/api";
import { Vue, Component, Watch } from "vue-property-decorator";
import { namespace } from "vuex-class";
import Router from "vue-router";
import { Message } from "element-ui";
import { LoginResponse, QRState } from "@/model/response-type.model";
const AppModule = namespace("app");
type TabType = "phone" | "password" | "qrcode";
@Component({})
export default class LoginDialogComponent extends Vue {
  tab: TabType = "password";
  showPassword = false;
  isCooling = false;
  coolingTime = 60;
  coolingTimer: any = null;
  form = {
    tele: "",
    teleErrorText: "",
    phone: {
      code: "",
      codeErrorText: "",
      password: "",
      passwordErrorText: "",
    },
    account: {
      password: "",
    },
  };
  qrcode = {
    key: "",
    src: "",
    expired: false,
  };

  $api: APIType;
  $router: Router;

  @AppModule.State("loginDialogVisible")
  loginDialogVisible: boolean;
  @AppModule.State("prevPath")
  prevPath: string;

  @AppModule.Mutation("setLoginDialogVisible")
  setLoginDialogVisible: (value: boolean) => void;
  @AppModule.Mutation("setUserInfo")
  public setUserInfo: (value: LoginResponse) => void;
  @AppModule.Mutation("setPrevPath")
  public setPrevPath: (value: string) => void;

  checkLoginDialogVisible(value: boolean) {
    if (this.loginDialogVisible !== value) {
      this.setLoginDialogVisible(value);
    }
  }
  async sendVerifyCode() {
    if (this.isCooling) {
      return;
    } else if (!/\d{11}/.test(this.form.tele)) {
      Message.warning("请输入11位手机号码");
    };
    this.$api.setVerifyCode(this.form.tele).then();
    this.isCooling = true;
  }
  checkInput() {
    if (!this.loginDialogVisible) return;
    let hasError = 0;
    switch (this.tab) {
      case "phone":
      case "password":
        if (!/\d{11}/.test(this.form.tele)) {
          this.form.teleErrorText = "请输入11位手机号";
          hasError++;
        } else {
          this.form.teleErrorText = "";
        }
        break;
    }
    return hasError;
  }
  clearCoolingTimer() {
    if (this.coolingTimer != null) {
      clearInterval(this.coolingTimer);
      this.coolingTimer = null;
    }
  }
  reduceCoolingTime() {
    this.clearCoolingTimer();
    this.coolingTime = 60;
    this.coolingTimer = setInterval(() => {
      this.coolingTime--;
    }, 1000);
  }
  register() {
    this.$api.register(this.form.tele, this.form.phone.password, this.form.phone.code, this.form.tele).then(res => {
      if (res.account) {
        Message.success("注册成功");
        this.loginSuccessAction(res);
      } else {
        Message.warning(`注册失败 ${(res as any)?.msg ?? ''}`);
      }
    }).catch(err => {
      Message.warning(`注册失败 ${(err?.response as any)?.data?.msg ?? ''}`);
    });
  }
  loginSuccessAction(res: LoginResponse) {
    window.sessionStorage.setItem("cookie", res.cookie);
    this.closeSimpleDialog();
    this.setUserInfo(res);
    const path = this.prevPath || "/";
    this.setPrevPath(null);
    this.$router.push(path);
  }
  login() {
    this.$api.loginByPassword(this.form.tele, this.form.account.password).then(res => {
    if (res?.account) {
        Message.success("登录成功");
        this.loginSuccessAction(res)
      } else {
        Message.warning(`登录失败 ${(res as any)?.msg ?? ''}`);
      }
    }).catch(err => {
      Message.warning(`登录失败 ${(err?.response as any)?.data?.msg ?? ''}`);
    });
  }
  closeSimpleDialog() {
    this.setLoginDialogVisible(false);
  }
  async checkQrCode() {
    let key: string;
    // 根据node项目中文档，二维码登录需要调用三个接口
    if (!this.qrcode.src || this.qrcode.expired) {
      // 第一个接口，获取一个key
      const res = await this.$api.getQRKey().catch((err) => {
        Message.warning("网络错误，请稍后再试");
        this.qrcode.expired = true;
        return err;
      });
      key = res?.data?.unikey;
    }
    if (!key) {
      this.qrcode.expired = true;
      return;
    }
    this.qrcode.key = key;
    // 第二个接口，得到二维码图片
    return this.$api.createQRCode(key).then(res => {
      if (!res?.data?.qrimg) {
        return Promise.reject(res);
      }
      this.qrcode.src = res.data.qrimg;
      this.qrcode.expired = false;
      // 第三个接口，轮询
      this.startQRCodeCheck();
    }).catch(err => {
      Message.warning("网络错误，请稍后再试");
      this.qrcode.expired = true;
      return err;
    });
  }
  qrCodeCheckTimer: any = null;
  startQRCodeCheck() {
    this.clearQRCodeCheck();
    this.qrCodeCheckTimer = setInterval(() => {
      this.$api.checkQrCode(this.qrcode.key).then(res => {
        switch (res?.code) {
          case QRState.Waiting:
          case QRState.Authorizing:
            break;
          case QRState.Expired:
            this.qrcode.expired = true;
            break;
          case QRState.Success:
            Message.success("登录成功");
            this.clearQRCodeCheck();
            window.sessionStorage.setItem("cookie", res.cookie);
            this.$api.loginStatus().then(rep => {
              if (rep?.account) {
                this.loginSuccessAction(rep);
              }
            });
            break;
          default:
            if (res?.code < 800) {
              return Promise.reject(res);
            }
            break;
        }
        return res;
      }).catch(err => {
        Message.warning("网络错误，请稍后再试");
      })
    }, 2000);
  }
  clearQRCodeCheck() {
    if (this.qrCodeCheckTimer) {
      clearInterval(this.qrCodeCheckTimer);
      this.qrCodeCheckTimer = null;
    }
  }
  @Watch("isCooling")
  isCoolingChange(value: boolean, oldValue: boolean) {
    if (value) {
      this.reduceCoolingTime();
    } else {
      this.clearCoolingTimer();
    }
  }
  @Watch("coolingTime")
  coolingTimeChange(value: number) {
    if (value <= 0) {
      this.clearQRCodeCheck();
      this.isCooling = false;
    }
  }
  @Watch("tab")
  private onTabChange(value: TabType) {
    if (value === "qrcode") {
      this.checkQrCode().then();
    } else {
      this.clearQRCodeCheck();
    }
  }
}
</script>
<style lang="scss" scoped>
.verify-code-box{
  position: relative;
  .verify-code-right{
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
  }
}
.qrcode-box{
  position: relative;
  width: 2rem;
  height: 2rem;
  .qrcode-mask {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.3);
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    .icon-span{
      color: #fff;
      font-size: 1rem;
    }
  }
  .img-box{
    width: 100%;
    height: 100%;
  }
}
</style>
